package ar.edu.unicen.exa.isistan.archassis.rcs.svn;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNDiffClient;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNUpdateClient;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

import ar.edu.unicen.exa.isistan.archassis.DiffRequestData;
import ar.edu.unicen.exa.isistan.archassis.rcs.IRevisionControlSystem;
import ar.edu.unicen.exa.isistan.archassis.rcs.IVersion;
import ar.edu.unicen.exa.isistan.archassis.rcs.RCSException;
import ar.edu.unicen.exa.isistan.archassis.rcs.RCSFileDiff;
import ar.edu.unicen.exa.isistan.archassis.rcs.RCSFileDiffList;
import ar.edu.unicen.exa.isistan.archassis.rcs.RCSFileModification;

public class SVNRevisionControlSystem implements IRevisionControlSystem {
	private SVNRepository repository = null;
	private SVNURL svnURL = null;
	private DiffRequestData diffRequestData = null;
	
	private String userSVNURL = "";
	
	public SVNRevisionControlSystem(String svnURL0) throws SVNRCSException {
		this.userSVNURL = svnURL0;
		this.diffRequestData = new DiffRequestData(svnURL0);
		
        ISVNAuthenticationManager authManager = null;

        DAVRepositoryFactory.setup();	

        try {
        	this.svnURL = SVNURL.parseURIDecoded( svnURL0 );
			repository = SVNRepositoryFactory.create(svnURL , null );
	        authManager = SVNWCUtil.createDefaultAuthenticationManager(); 
	        repository.setAuthenticationManager( authManager ); 
	
	        //SVNUpdateClient client = new SVNUpdateClient(authManager , SVNWCUtil.createDefaultOptions(true));

        } catch (SVNException e) {
        	throw new SVNRCSException(e);
		} 
	}
	@Override
	public void checkOut(IVersion v, List<RCSFileDiff> items, DiffRequestData tmpFile) throws RCSException {
		//cliente para checkoutear
		SVNUpdateClient client = SVNClientManager.newInstance().getUpdateClient();
		
		//parametros para el exportador
		
		SVNRevision pegRevision = SVNRevision.UNDEFINED;
		SVNRevision svnrevision = ((SVNVersion)v).getSVNRevision();
		String eolStyle = null;
		boolean overwrite = true;
		SVNDepth depth = SVNDepth.INFINITY;
		int i = 0;
		
		for (RCSFileDiff fileDiff : items) {
			File dstPath = tmpFile.getDestinationFor(v, fileDiff);//new File(dir, fileDiff.getPath());
			File dstPathError = new File(dstPath.getAbsolutePath() + ".error");
			System.out.println("CO " + i + " de " + items.size() + " en " + dstPath.getAbsolutePath());
			try {
				if (fileDiff.getPath().endsWith(".java")) {
					
					if ((! dstPath.isFile()) && (! dstPathError.isFile())){
						SVNURL url = SVNURL.parseURIDecoded(svnURL.toString() + "/" + fileDiff.getPath());
						client.doExport(url, dstPath, pegRevision, svnrevision, eolStyle, overwrite, depth);
						System.out.println("bajo bien " + fileDiff.getPath());
					} else {
						System.out.println("ya existia " + fileDiff.getPath());
					}
				}
			} catch (Exception e) {
				
				if (RCSFileModification.MODIFIED.equals(fileDiff.getModificationType())) {
					throw new SVNRCSException(e);
				}
				printStackTrace(e, dstPathError);
	        }
			i++;
		}

	}
	
	@Override
	public RCSFileDiffList getDiff(IVersion v0, IVersion v1) throws SVNRCSException {
		SVNRevision firstRevision = ((SVNVersion)v0).getSVNRevision();
		SVNRevision lastRevision = ((SVNVersion)v1).getSVNRevision();
		
		SVNClientManager clientManager = SVNClientManager.newInstance();

        SVNDiffClient diffClient = clientManager.getDiffClient();
        
        try {
	        SVNDiffList diffList = new SVNDiffList();
	        
			diffClient.doDiffStatus(svnURL, 
					firstRevision, 
					lastRevision, 
					SVNRevision.UNDEFINED, SVNDepth.INFINITY, true,
					diffList);
			
			return new RCSFileDiffList(diffList.toList());
        } catch (Exception e) {
        	throw new SVNRCSException(e);
        }
	}

	@Override
	public IVersion getLastVersion() throws RCSException {
		try {
			long latestRevision = repository.getLatestRevision();
			
			SVNProperties properties = repository.getRevisionProperties(latestRevision, null);
			IVersion e = new SVNVersion(latestRevision, properties);
			return e;
		} catch (Exception e) {
			throw new SVNRCSException(e);
		}
	}
	
	@Override
	public List<IVersion> getVersions() throws RCSException {
		try {
			long latestRevision = repository.getLatestRevision();
			List<IVersion> list = new ArrayList<IVersion>();
			for (int i = 1; i <= latestRevision; i++) {
				System.out.println(i + " de " + latestRevision + ": Obteniendo propiedades");
				IVersion e = loadIVersion(i);
				
				list.add(e);
			}
			return list;
		} catch (Exception e) {
			throw new SVNRCSException(e);
		}
	}
	
	private IVersion loadIVersion(long r) throws SVNException {
		SVNProperties properties = repository.getRevisionProperties(r, null);
		IVersion e = new SVNVersion(r, properties);
		return e;
	}

	private static void printStackTrace(Throwable t, File f) {
		String ex = getStackTrace(t);
		try{
			f.getParentFile().mkdirs();
			  // Create file 
			  FileWriter fstream = new FileWriter(f);
			  BufferedWriter out = new BufferedWriter(fstream);
			  out.write(ex);
			  //Close the output stream
			  out.close();
			  }catch (Exception e){//Catch exception if any
			  System.err.println("Error: " + e.getMessage());
			  }
	}
	
	
	private static String getStackTrace(Throwable t) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw, true);
        t.printStackTrace(pw);
        pw.flush();
        sw.flush();
        return sw.toString();
    }
	@Override
	public DiffRequestData getDiffRequestData() {
		return diffRequestData;
	}
	public String getUserSVNURL() {
		return userSVNURL;
	}
	public List<IVersion> getWorkingVersions() throws RCSException {
		Collection<SVNLogEntry> logEntries = null;
		try {
			logEntries = repository.log( new String[] { "" } , null , 0 , -1 , true , true );
		} catch (Exception e) {
			throw new SVNRCSException(e);
		}
		
		List<IVersion> list = new ArrayList<IVersion>();
		
		for (SVNLogEntry le : logEntries) {
			try {
				IVersion e = loadIVersion(le.getRevision());
				list.add(e);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return list;
	}

}